home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / getmat.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  20KB  |  829 lines

  1. /*
  2.  * $Id: getmat.c,v 0.91 1994/02/20 00:53:11 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * Low level supporting routines.
  26.  *
  27.  * WARNING:
  28.  * these are NOT general purposes stuff and all matrix routines have the
  29.  * following assumptions:
  30.  *  1. sizeof(char *)==sizeof(int *)==sizeof(long **)==sizeof(char **)
  31.  *  2. short alignment
  32.  */
  33.  
  34. #if !defined(lint) && defined(F_ID)
  35. char *id_mat = "$Id: getmat.c,v 0.91 1994/02/20 00:53:11 zhao Pre-Release $";
  36. #endif
  37.  
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include "utype.h"
  41. #include "ulib.h"
  42. #include "uproto.h"
  43. #include "dmalloc.h"
  44.  
  45. static int usecalloc;        /* use calloc instead of malloc if set */
  46.  
  47. void
  48. set_use_calloc(int y)
  49. {
  50.     usecalloc = y;
  51. }
  52.  
  53.  
  54. /***************************************************************
  55.  * make_mat will take a block of memory and assign the pointers
  56.  * so that we can use it as a matrix
  57.  ***************************************************************/
  58.  
  59. void
  60. make_mat(void *mat, void *mem, int nrow, int ncol, size_t esize)
  61. {
  62.     int i, j;
  63.     char **m = mat;
  64.  
  65.     m[0] = mem;
  66.  
  67.     j = ncol * esize;
  68.     for (i = 1; i < nrow; i++)
  69.     m[i] = m[i - 1] + j;
  70. }
  71.  
  72. #ifndef M_DBG
  73.  
  74. /*
  75.  * if M_DBG is set, get_mat will be replaced by another function which
  76.  * will remember where it is called
  77.  */
  78.  
  79. /*********************************************************************
  80.  * get a matrix  of nrow * ncol with element size of esize bytes.
  81.  *********************************************************************/
  82.  
  83. void *
  84. get_mat(int nrow, int ncol, size_t esize)
  85. {
  86.     register char **m;
  87.     void *p;
  88.  
  89.     if (nrow < 1 || ncol < 1)
  90.       {
  91.       M_err("Getmatrix", "Bad parameters c=%d r=%d", ncol, nrow);
  92.       return 0;
  93.       }
  94.  
  95.     if (!(m = malloc(sizeof(void *) * nrow)))
  96.       {
  97.       M_err("Getmatrix", "GetMatrix: malloc failure");
  98.       return 0;
  99.       }
  100.  
  101.     if (!(p = usecalloc ? calloc(nrow * ncol, esize) :
  102.       malloc(esize * nrow * ncol)))
  103.       {
  104.       M_err("Getmatrix", "GetMatrix: malloc failure");
  105.       return 0;
  106.       }
  107.  
  108.     /* make the matrix */
  109.     make_mat(m, p, nrow, ncol, esize);
  110.     return m;
  111. }
  112.  
  113. #else /* ! M_DBG */
  114.  
  115. /*******************************************************************
  116.  * Debug version of get_mat: f and line are the file and line number
  117.  * where get_mat is called
  118.  *******************************************************************/
  119.  
  120. void *
  121. dbg_getmat(int nrow, int ncol, size_t esize, const char *f, int line)
  122. {
  123.     register char **m;
  124.     char ff[1024];
  125.     void *p;
  126.  
  127.     if (nrow < 1 || ncol < 1)
  128.       {
  129.       M_err("Getmatrix", "Bad parameters c=%d r=%d", ncol, nrow);
  130.       return 0;
  131.       }
  132.  
  133.     /* construct a complete name */
  134.     strcpy(ff, "getmat_");
  135.     strncat(ff, f, sizeof(ff) - 10);
  136.  
  137.     m = dbg_malloc(sizeof(void *) * nrow, ff, line);
  138.  
  139.     p = usecalloc ? dbg_calloc(nrow * ncol, esize, ff, line) :
  140.     dbg_malloc(esize * nrow * ncol, ff, line);
  141.  
  142.     if (!m || !p)
  143.       {
  144.       if (m)
  145.           free(m);
  146.       if (p)
  147.           free(p);
  148.       M_err("Getmatrix", "GetMatrix: malloc failure");
  149.       return 0;
  150.       }
  151.  
  152.     /* make the matrix */
  153.     make_mat(m, p, nrow, ncol, esize);
  154.     return m;
  155. }
  156.  
  157. #endif
  158.  
  159. /*************************************************************
  160.  * free a matrix allocated by Getmatrix
  161.  **************************************************************/
  162.  
  163. void
  164. free_mat(void *p)
  165. {
  166.     char **m = p;
  167.  
  168.     if (p && m[0])
  169.       {
  170.       free(m[0]);
  171.       m[0] = 0;
  172.       free(p);
  173.       }
  174. }
  175.  
  176. /*************************************************************
  177.  * get a three-d tensor T[d1][d2][d3]
  178.  *************************************************************/
  179.  
  180. void *
  181. get_3d(int d1, int d2, int d3, size_t es)
  182. {
  183.     char **m;
  184.     int i;
  185.  
  186.     /*
  187.      * we got one more, then the freeing routine will have easier time figure
  188.      * out the leading dimension
  189.      */
  190.  
  191.     m = malloc(sizeof(void *) * (d1 + 1));
  192.  
  193.     for (i = 0; i < d1; i++)
  194.     m[i] = get_mat(d2, d3, es);
  195.     m[d1] = 0;
  196.  
  197.     return m;
  198. }
  199.  
  200. /******** free the tensor gotten by get_3d ********/
  201. void
  202. free_3d(void *p)
  203. {
  204.     char **m = p;
  205.  
  206.     if (p && m[0])
  207.       {
  208.       while (*m)
  209.         {
  210.         free_mat(*m);
  211.         *m = 0;
  212.         m++;
  213.         }
  214.       }
  215. }
  216.  
  217.  
  218.  
  219. /****************************************************************
  220.  * Pack a R,G,B into a RGBA. Special provisions are made for
  221.  * grayscale images, signified by r==g
  222.  ***************************************************************/
  223.  
  224. void
  225. pack_mat(register rgba_t *m, register pc_t *r, register pc_t *g,
  226.      register pc_t *b, long total)
  227. {
  228.     register pc_t *rend;
  229.  
  230.     if (r != g)
  231.       {
  232.       for (rend = r + total; r < rend; r++, g++, b++, m++)
  233.           *m = Pack(*r, *g, *b);
  234.       }
  235.     else
  236.       {
  237.       for (rend = r + total; r < rend; r++, m++)
  238.           *m = Pack(*r, *r, *r);
  239.       }
  240.  
  241. }
  242.  
  243. /* unpack */
  244. void
  245. unpack_mat(register rgba_t *m,
  246.        register pc_t *r, register pc_t *g, register pc_t *b,
  247.        long total)
  248. {
  249.     register pc_t *rend;
  250.  
  251.     if (r != g)
  252.       {
  253.       for (rend = r + total; r < rend; r++, g++, b++, m++)
  254.           Unpack(*m, *r, *g, *b);
  255.       }
  256.     else
  257.       {
  258.       for (rend = r + total; r < rend; r++, m++)
  259.           *r = get_R(*m);
  260.       }
  261. }
  262.  
  263. /*****************************************************************
  264.  * Initialize a submatrix to m0
  265.  *****************************************************************/
  266. void
  267. init_mat(void *m, int rows, int cols, size_t esize, unsigned long m0)
  268. {
  269.     if (esize == sizeof(rgba_t))
  270.       {
  271.       register rgba_t *p = ((rgba_t **) m)[0], *ps = p + rows * cols;
  272.       while (--ps >= p)
  273.           *ps = m0;
  274.       }
  275.     else
  276.       {
  277.       register ci_t *p = ((ci_t **) m)[0], *ps = p + rows * cols;
  278.       while (--ps >= p)
  279.           *ps = m0;
  280.       }
  281. }
  282.  
  283. /*****************************************************************
  284.  * given a matrix, get a submatrix out of it. r,c are the original
  285.  * matrix order and rr,cc are the submatrix order r1 and c1 are
  286.  * the starting posisiton. Should never be called directly by any
  287.  * routine other than subimage routines.
  288.  ****************************************************************/
  289.  
  290. /* ARGSUSED */
  291. void *
  292. get_submat(void *in, int r, int c,
  293.        int r1, int c1, int rr, int cc, size_t esize)
  294. {
  295.     register int r2 = r1 + rr - 1;
  296.     register int i, err, off = esize * c1;
  297.     register size_t size = esize * cc;
  298.     register char **nm, **om = in;
  299.  
  300. #ifdef CHECK_MAT
  301.  
  302.     if (rr > r || cc > cc || r1 < 0 || c1 < 0)
  303.       {
  304.       M_warn("GetSubMat", "Bad function parameters");
  305.       return 0;
  306.       }
  307. #endif
  308.  
  309.     if (!(nm = get_mat(rr, cc, esize)))
  310.     return 0;
  311.  
  312.     for (i = r1, err = 0; i <= r2 && !err; i++)
  313.     err = memcpy(nm[i - r1], om[i] + off, size) == 0;
  314.  
  315.     if (err)
  316.       {
  317.       free_mat(nm);
  318.       nm = 0;
  319.       }
  320.  
  321.     return nm;
  322. }
  323.  
  324. /**********************************************************************
  325.  * Things to do when putting back a submatrix.
  326.  * Note that there is no way we can do meaningful things except Masking
  327.  * with CI images and therefore, when esize == 2, ignore matop request
  328.  ****************************************************************/
  329.  
  330. static Matop_t matop = O_NONE;    /* current op mode     */
  331. static rgba_t magicpix;        /* masking magic pixel */
  332.  
  333. /**** set the operations to do when putting a submatrix back ***/
  334. void
  335. set_mat_op(Matop_t m)
  336. {
  337.     matop = m;
  338. }
  339.  
  340. /******* get current settings ******/
  341. Matop_t
  342. get_mat_op(void)
  343. {
  344.     return matop;
  345. }
  346.  
  347. /*****************************************************************
  348.  * What the masking "magic" pixel is. Default is black.
  349.  * Keep RGB only. This is sort of broken as theoretically
  350.  * there is no "free" pixel for the magic pixel. Alpha
  351.  * channel is the best for these kind of things.
  352.  ****************************************************************/
  353. void
  354. set_magic_pix(rgba_t m)
  355. {
  356.     magicpix = m & 0x00ffffff;
  357. }
  358.  
  359. /***** get current magic pixel ****/
  360. rgba_t
  361. get_magic_pix(void)
  362. {
  363.     return magicpix;
  364. }
  365.  
  366. /**********************************************************
  367.  * replace part of a matrix with a new matrix, after performing
  368.  * defined operations: Add, sub, mask etc
  369.  ***********************************************************/
  370.  
  371. static void
  372. mask_submat(char **dest, char **src, int nr, int nc,
  373.         int off, size_t esize)
  374. {
  375.     register int r;
  376.  
  377.     if (esize == sizeof(rgba_t))
  378.       {
  379.       register rgba_t *ras, *rase, *ss;
  380.       for (r = 0; r < nr; r++)
  381.         {
  382.         ss = (rgba_t *) src[r];
  383.         ras = (rgba_t *) (dest[r] + off);
  384.         for (rase = ras + nc; ras < rase; ras++, ss++)
  385.             *ras = ((*ss & 0x00ffffff) != magicpix ? *ss : *ras);
  386.         }
  387.       }
  388.     else
  389.       {
  390.       register ci_t *ras, *rase, *ss;
  391.       for (r = 0; r < nr; r++)
  392.         {
  393.         ss = (ci_t *) src[r];
  394.         ras = (ci_t *) (dest[r] + off);
  395.         for (rase = ras + nc; ras < rase; ras++, ss++)
  396.             *ras = (*ss != magicpix ? *ss : *ras);
  397.         }
  398.       }
  399. }
  400.  
  401. static void
  402. add_submat(char **dest, char **src, int nr, int nc,
  403.        int off, size_t esize)
  404. {
  405.     register int r;
  406.  
  407.     if (esize == sizeof(rgba_t))
  408.       {
  409.       register rgba_t *ras, *rase, *ss;
  410.       int pc1[3], pc2[3];
  411.  
  412.       for (r = 0; r < nr; r++)
  413.         {
  414.         ss = (rgba_t *) src[r];
  415.         ras = (rgba_t *) (dest[r] + off);
  416.         for (rase = ras + nc; ras < rase; ras++, ss++)
  417.           {
  418.               Unpack(*ras, pc1[0], pc1[1], pc1[2]);
  419.               Unpack(*ss, pc2[0], pc2[1], pc2[2]);
  420.               if ((pc1[0] += pc2[0]) > PCMAXV)
  421.               pc1[0] = PCMAXV;
  422.               if ((pc1[1] += pc2[1]) > PCMAXV)
  423.               pc1[1] = PCMAXV;
  424.               if ((pc1[2] += pc2[2]) > PCMAXV)
  425.               pc1[2] = PCMAXV;
  426.               *ras = Pack(pc1[0], pc1[1], pc1[2]);
  427.           }
  428.         }
  429.       }
  430.     else
  431.       {
  432.       register ci_t *ras, *rase, *ss;
  433.       for (r = 0; r < nr; r++)
  434.         {
  435.         ss = (ci_t *) src[r];
  436.         ras = (ci_t *) (dest[r] + off);
  437.         for (rase = ras + nc; ras < rase; ras++, ss++)
  438.             *ras = *ss;
  439.         }
  440.       }
  441. }
  442.  
  443. static void
  444. sub_submat(char **dest, char **src, int nr, int nc,
  445.        int off, size_t esize)
  446. {
  447.     int r;
  448.  
  449.     if (esize == sizeof(rgba_t))
  450.       {
  451.       register rgba_t *ras, *rase, *ss;
  452.       int pc1[3], pc2[3];
  453.  
  454.       for (r = 0; r < nr; r++)
  455.         {
  456.         ss = (rgba_t *) src[r];
  457.         ras = (rgba_t *) (dest[r] + off);
  458.         for (rase = ras + nc; ras < rase; ras++, ss++)
  459.           {
  460.               Unpack(*ras, pc1[0], pc1[1], pc1[2]);
  461.               Unpack(*ss, pc2[0], pc2[1], pc2[2]);
  462.               if ((pc1[0] -= pc2[0]) < 0)
  463.               pc1[0] = 0;
  464.               if ((pc1[1] -= pc2[1]) < 0)
  465.               pc1[1] = 0;
  466.               if ((pc1[2] -= pc2[2]) < 0)
  467.               pc1[2] = 0;
  468.               *ras = Pack(pc1[0], pc1[1], pc1[2]);
  469.           }
  470.         }
  471.       }
  472.     else
  473.       {
  474.       register ci_t *ras, *rase, *ss;
  475.       for (r = 0; r < nr; r++)
  476.         {
  477.         ss = (ci_t *) src[r];
  478.         ras = (ci_t *) (dest[r] + off);
  479.         for (rase = ras + nc; ras < rase; ras++, ss++)
  480.             *ras = *ss;
  481.         }
  482.       }
  483. }
  484.  
  485. static void
  486. diff_submat(char **dest, char **src, int nr, int nc,
  487.         int off, size_t esize)
  488. {
  489.     register int r;
  490.  
  491.     if (esize == sizeof(rgba_t))
  492.       {
  493.       register rgba_t *ras, *rase, *ss;
  494.       int pc1[3], pc2[3];
  495.  
  496.       for (r = 0; r < nr; r++)
  497.         {
  498.         ss = (rgba_t *) src[r];
  499.         ras = (rgba_t *) (dest[r] + off);
  500.         for (rase = ras + nc; ras < rase; ras++, ss++)
  501.           {
  502.               Unpack(*ras, pc1[0], pc1[1], pc1[2]);
  503.               Unpack(*ss, pc2[0], pc2[1], pc2[2]);
  504.               if ((pc1[0] -= pc2[0]) < 0)
  505.               pc1[0] = -pc1[0];
  506.               if ((pc1[1] -= pc2[1]) < 0)
  507.               pc1[1] = -pc1[1];
  508.               if ((pc1[2] -= pc2[2]) < 0)
  509.               pc1[2] = pc1[2];
  510.               *ras = Pack(pc1[0], pc1[1], pc1[2]);
  511.           }
  512.         }
  513.       }
  514.     else
  515.       {
  516.       register ci_t *ras, *rase, *ss;
  517.       for (r = 0; r < nr; r++)
  518.         {
  519.         ss = (ci_t *) src[r];
  520.         ras = (ci_t *) (dest[r] + off);
  521.         for (rase = ras + nc; ras < rase; ras++, ss++)
  522.             *ras = *ss;
  523.         }
  524.       }
  525. }
  526.  
  527. static void
  528. xor_submat(char **dest, char **src, int nr, int nc,
  529.        int off, size_t esize)
  530. {
  531.     int r;
  532.  
  533.     if (esize == sizeof(rgba_t))
  534.       {
  535.       register rgba_t *ras, *rase, *ss;
  536.  
  537.       for (r = 0; r < nr; r++)
  538.         {
  539.         ss = (rgba_t *) src[r];
  540.         ras = (rgba_t *) (dest[r] + off);
  541.         for (rase = ras + nc; ras < rase; ras++, ss++)
  542.             *ras ^= *ss;
  543.         }
  544.       }
  545.     else
  546.       {
  547.       register ci_t *ras, *rase, *ss;
  548.       for (r = 0; r < nr; r++)
  549.         {
  550.         ss = (ci_t *) src[r];
  551.         ras = (ci_t *) (dest[r] + off);
  552.         for (rase = ras + nc; ras < rase; ras++, ss++)
  553.             *ras ^= *ss;
  554.         }
  555.       }
  556. }
  557.  
  558. /*****************************************************************
  559.  * Insert a (smaller) matrix new into another (larger) matrix old
  560.  *
  561.  ****************************************************************/
  562. /* ARGSUSED */
  563. int
  564. put_submat(void *old, int orow, int ocol,
  565.        void *new, int r1, int c1, int rr, int cc,
  566.        size_t esize)
  567. {
  568.     int r2 = r1 + rr - 1;
  569.     register int err = 0, r, off = esize * c1;
  570.     register char **dest = old, **src = new;
  571.     register size_t size = esize * cc;
  572.  
  573. #ifdef CHECK_MAT
  574.     if (r1 < 0 || c1 < 0 || r2 >= orow || (cc + c1 - 1) >= ocol)
  575.       {
  576.       M_warn("PutSubMat", "Bad input");
  577.       return -1;
  578.       }
  579. #endif
  580.  
  581.     /*
  582.      * if no operation or matrix is color index, simple put the matrix back,
  583.      * i.e., overwrite
  584.      */
  585.  
  586.     switch (matop)
  587.       {
  588.       case O_MASK:
  589.       mask_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
  590.       break;
  591.       case O_ADD:
  592.       add_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
  593.       break;
  594.       case O_SUB:
  595.       sub_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
  596.       break;
  597.       case O_DIFF:
  598.       diff_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
  599.       break;
  600.       case O_XOR:
  601.       xor_submat(dest + r1, src - r1, rr + 1, cc + 1, off, esize);
  602.       break;
  603.       default:
  604.       for (r = r1; r <= r2 && !err; r++)
  605.           err = memcpy(dest[r] + off, src[r - r1], size) == 0;
  606.       break;
  607.       }
  608.  
  609.     return err ? -1 : 0;
  610. }
  611.  
  612. /**************************************************************
  613.  * fill a submatrix with a particular val
  614.  **************************************************************/
  615.  
  616. #define Fill_submat(type, fill)                              \
  617.    do {                                                      \
  618.        register type **mat = m;                              \
  619.        for ( r = r1; r <= r2; r++)                           \
  620.            for ( c = c1; c <= c2; c++)                       \
  621.                mat[r][c] = fill;                             \
  622.    } while (ZERO)
  623.  
  624. void
  625. fill_submat(void *m, int r1, int r2, int c1, int c2, rgba_t f, size_t e)
  626. {
  627.     register ci_t cfill = (ci_t) f;
  628.     register int r, c;
  629.  
  630. #ifdef CHECK_MAT
  631.     if (r1 < 0 || c1 < 0)
  632.       {
  633.       M_warn("FillSubMat", "Bad input");
  634.       return;
  635.       }
  636. #endif
  637.     if (e == sizeof(rgba_t))
  638.       Fill_submat(rgba_t, f);
  639.     else if (e == sizeof(ci_t))
  640.       Fill_submat(ci_t, cfill);
  641. }
  642.  
  643. /*****************************************************
  644.  * flip a matrix (mirror operations)
  645.  ****************************************************/
  646. #define flip_col(type)                                             \
  647.        do {                                                        \
  648.            register type **mm = m, *t, *h, tmp; int    j;          \
  649.            for (j = 0; j < r; j++)                                 \
  650.                for (t = (h = mm[j]) + (c - 1); t > h; t--, h++) {  \
  651.                    tmp = *h; *h = *t; *t = tmp;                    \
  652.            }                                                       \
  653.        } while(ZERO)
  654.  
  655. int
  656. flip_mat(void *m, int r, int c, int f, size_t e)
  657. {
  658.  
  659. #ifdef CHECK_MAT
  660.     if (!m || (e != sizeof(ci_t) && e != sizeof(rgba_t)))
  661.       {
  662.       M_warn("FlipMat", "Bad matrix");
  663.       return -1;
  664.       }
  665. #endif
  666.  
  667.     switch (f)
  668.       {
  669.       case 'r':        /* flip rows */
  670.       case 'y':
  671.       {
  672.           register int i, is = (r / 2);
  673.           register size_t size = e * c;
  674.           register char *tmp, **mm = m;
  675.  
  676.           if (!(tmp = malloc(size)))
  677.           return -1;
  678.           for (i = 0; i < is; i++)
  679.         {
  680.             (void) memcpy(tmp, mm[i], size);
  681.             (void) memcpy(mm[i], mm[r - 1 - i], size);
  682.             (void) memcpy(mm[r - 1 - i], tmp, size);
  683.         }
  684.           free(tmp);
  685.       }
  686.       break;
  687.       case 'c':
  688.       case 'x':        /* flip colums */
  689.       if (e == sizeof(ci_t))
  690.         {
  691.         flip_col(ci_t);
  692.         }
  693.       else
  694.         {
  695.         flip_col(rgba_t);
  696.         }
  697.       break;
  698.  
  699.       default:            /* error */
  700.       M_err("FlipMat", "Bad request");
  701.       return -1;
  702.       }
  703.     return 0;
  704. }
  705.  
  706. static int
  707. check_funcp(void *m, int nr, int nc, size_t e, const char *f)
  708. {
  709.     if (!m)
  710.       {
  711.       M_warn(f, "Bad input matrix");
  712.       return -1;
  713.       }
  714.  
  715.     if (nr < 1 || nc < 1)
  716.       {
  717.       M_warn(f, "Bad matrix dimension: nr=%d nc=%d", nr, nc);
  718.       }
  719.  
  720.     if (e != sizeof(ci_t) && e != sizeof(rgba_t))
  721.       {
  722.       M_warn(f, "Bad input matrix element size %d", e);
  723.       return -1;
  724.       }
  725.     return 0;
  726. }
  727.  
  728. /***************************************************************
  729.  * rotate a matrix by 90, or -90 or multiples of it
  730.  * Rotate 180 can be implented as two 90 rotations, but current
  731.  * code is faster.
  732.  *
  733.  * NOTE: input dimension is the diemsnion of the matrix to be
  734.  *       rotated. caller must take care of the rotated dimensions
  735.  **************************************************************/
  736. /*
  737.  * Rotate 90 degrees
  738.  */
  739. #define DO_90(type)                                            \
  740.            do {                                                \
  741.              register type *p= ((type **)mm)[0], **oo= m;      \
  742.              register int i, j;                                \
  743.              for ( j= 0; j < col; j++) {                       \
  744.                 for (i= row-1; i>=0; i--) *p++ = oo[i][j];     \
  745.              }                                                 \
  746.            } while (ZERO)
  747. /*
  748.  * Rotate -90 degrees
  749.  */
  750.  
  751. #define DO_M90(type)                                          \
  752.            do {                                               \
  753.               register type *p= ((type **) mm)[0], **o= m;    \
  754.               register int i, j;                              \
  755.               for (j= col - 1; j >= 0; j--) {                 \
  756.                  for (i= 0; i < row; i++) *p++ = o[i][j];     \
  757.                }                                              \
  758.            } while (ZERO)
  759.  
  760. #define DO_180(ty)                                            \
  761.            do {                                               \
  762.              register ty *p= ((ty **)mm)[0], *o=((ty **)m)[0];\
  763.              register  ty *os;                                \
  764.              for (os= o + col*row-1 ; os>o; *p++ = *os--) ;   \
  765.            } while(ZERO)
  766.  
  767. void *
  768. rotate_mat(void *m, int row, int col, int deg, size_t e)
  769. {
  770.     void *mm;
  771.     int nrow, ncol;
  772.  
  773.     if (check_funcp(m, row, col, e, "Rotate:"))
  774.     return 0;
  775.  
  776.     if (deg == 90 || deg == -90)
  777.       {
  778.       nrow = col;
  779.       ncol = row;
  780.       }
  781.     else
  782.       {
  783.       nrow = row;
  784.       ncol = col;
  785.       }
  786.  
  787.     if (!(mm = get_mat(nrow, ncol, e)))
  788.     return 0;
  789.  
  790.     if (deg == 90)
  791.       {
  792.       if (e == sizeof(rgba_t))
  793.         {
  794.         DO_90(rgba_t);
  795.         }
  796.       else
  797.         {
  798.         DO_90(ci_t);
  799.         }
  800.       }
  801.     else if (deg == -90)
  802.       {
  803.       if (e == sizeof(rgba_t))
  804.         {
  805.         DO_M90(rgba_t);
  806.         }
  807.       else
  808.         {
  809.         DO_M90(ci_t);
  810.         }
  811.       }
  812.     else if (deg == 180 || deg == -180)
  813.       {
  814.       if (e == sizeof(rgba_t))
  815.         {
  816.         DO_180(rgba_t);
  817.         }
  818.       else
  819.         {
  820.         DO_180(ci_t);
  821.         }
  822.       }
  823.     else
  824.       {
  825.       M_warn("RotMat", "Bad angle %d", deg);
  826.       }
  827.     return mm;
  828. }
  829.